package com.gzhryc.servlet.upload;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

import com.gzhryc.common.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

public class StorageService {

    static Logger log = Logger.getLogger(StorageService.class);
    
    static StorageService self;
    
    // 保存文件的根目录
    private final String rootPath;

    public StorageService(String rootPath) {
    	if(StringUtils.isNotBlank(rootPath) && !rootPath.equals("/")){
    		this.rootPath = rootPath;
    	}else{
    		this.rootPath = "";
    	}
    }

    public static StorageService init(String rootPath) {
    	self = new StorageService(rootPath);
    	return self;
    }
    
    public static StorageService get(){
    	return self;
    }

    public boolean uploadFileByMappedByteBuffer(MultipartFileParam param,String tempPath,String dirPath) throws IOException {
        String fileName = param.getName();
        String uploadDirPath = rootPath + tempPath + File.separatorChar  + param.getMd5();
        String tempFileName = fileName + "_tmp";
        File tmpDir = new File(uploadDirPath);
        File tmpFile = new File(uploadDirPath, tempFileName);
        if (!tmpDir.exists()) {
            tmpDir.mkdirs();
        }
        RandomAccessFile tempRaf = new RandomAccessFile(tmpFile, "rw");
        FileChannel fileChannel = tempRaf.getChannel();

        //写入该分片数据
        long offset = param.getChunkSize() * param.getChunk();
        byte[] fileData = param.getFile().get();
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, offset, fileData.length);
        mappedByteBuffer.put(fileData);
        fileChannel.close();
        tempRaf.close();
        
        boolean isOk = checkAndSetUploadProgress(param, uploadDirPath);
        if (isOk) {
            String newFileName = rootPath + dirPath + File.separatorChar + fileName;
            try {
                FileUtils.copyFile(tmpFile, new File(newFileName));
            }catch (IOException e){
                log.error(e.getMessage(),e);
                isOk = false;
            }
            if(isOk) {
                try {
                    FileUtils.deleteDirectory(tmpFile.getParentFile());
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            return isOk;
        }
        return false;
    }

    /**
     * 检查并修改文件上传进度
     *
     * @param param
     * @param uploadDirPath
     * @return
     * @throws IOException
     */
    private boolean checkAndSetUploadProgress(MultipartFileParam param, String uploadDirPath) throws IOException {
        String fileName = param.getName();
        File confFile = new File(uploadDirPath, fileName + ".conf");
        RandomAccessFile accessConfFile = new RandomAccessFile(confFile, "rw");
        //把该分段标记为 true 表示完成
        System.out.println("set part " + param.getChunk() + " complete");
        accessConfFile.setLength(param.getChunks());
        accessConfFile.seek(param.getChunk());
        accessConfFile.write(Byte.MAX_VALUE);

        //completeList 检查是否全部完成,如果数组里是否全部都是(全部分片都成功上传)
        byte[] completeList = FileUtils.readFileToByteArray(confFile);
        byte isComplete = Byte.MAX_VALUE;
        for (int i = 0; i < completeList.length && isComplete == Byte.MAX_VALUE; i++) {
            //与运算, 如果有部分没有完成则 isComplete 不是 Byte.MAX_VALUE
            isComplete = (byte) (isComplete & completeList[i]);
            System.out.println("check part " + i + " complete?:" + completeList[i]);
        }

        accessConfFile.close();
        if (isComplete == Byte.MAX_VALUE) {
        	CacheManager.create().getCache(UploadConstants.FILE_UPLOAD_STATUS).put(new Element(param.getMd5(),true));
        	CacheManager.create().getCache(UploadConstants.FILE_MD5_KEY).put(new Element(param.getMd5(), uploadDirPath + "/" + fileName));
            return true;
        } else {
            if (!CacheManager.create().getCache(UploadConstants.FILE_UPLOAD_STATUS).isKeyInCache(param.getMd5())) {
            	CacheManager.create().getCache(UploadConstants.FILE_UPLOAD_STATUS).put(new Element(param.getMd5(),false));
            }
            if (CacheManager.create().getCache(UploadConstants.FILE_MD5_KEY).isKeyInCache(param.getMd5())) {
            	CacheManager.create().getCache(UploadConstants.FILE_MD5_KEY).put(new Element(param.getMd5(), uploadDirPath + "/" + fileName + ".conf"));
            }
            return false;
        }
    }
}
